﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Krile.Kernel.Control;
using Krile.Kernel.Data;
using Krile.Kernel;
using System.Windows.Forms;
using Krile.Kernel.Control.Surface;

namespace Wassrile.Controls
{
    public class FavDigest : MessageObject
    {
        public FavDigest() : base() { }

        public FavDigest(ref Operation.DataClasses.WStatus par)
            : base()
        {
            ParentStatus = par;
        }

        public Operation.DataClasses.WStatus ParentStatus;

        //Iconify size
        const int pictWidth = 16;
        const int pictHeight = 16;
        const int outerMargin = 2;
        const int innerPadding = 1;
        const int fontSize = 8;

        private void ImgDlCallback(Uri target,Image img)
        {
            lock (dictionaryLocker)
            {
                if (internalCache.ContainsKey(target))
                    internalCache[target] = img;
                else
                    internalCache.Add(target, img);
            }
            if (ParentForm != null)
                ParentForm.RefreshTLWeak(false);
        }

        private object dictionaryLocker = new object();
        Dictionary<Uri, Image> internalCache = new Dictionary<Uri, Image>();

        private object areaLocker = new object();
        private struct DescriptableAreas
        {
            public string Description;
            public Rectangle Area;
            public User LinkUser;
        }
        List<DescriptableAreas> areas = new List<DescriptableAreas>();
        public override void Composite(Compositor compz)
        {
            if (ParentStatus.FavoredUsers == null || ParentStatus.FavoredUsers.Length == 0)
                return;

            //First, move newline
            compz.MoveNewLine();

            //init
            compz.SetCurrentLineHeight(outerMargin + 1 + innerPadding);
            compz.MoveNewLine();
            Point tPoint = new Point(2 * (outerMargin + innerPadding + 1), 0);

            //start composite items
            for (int i = 0; i < ParentStatus.FavoredUsers.Length; i++)
            {
                Rectangle cur = new Rectangle(tPoint, new Size(pictWidth, pictHeight));
                tPoint.X += pictWidth;
                compz.SetCurrentLineHeight(pictHeight);
                if (tPoint.X > compz.ClientWidth || tPoint.X + pictWidth > compz.ClientWidth)
                {
                    tPoint.X = (outerMargin + innerPadding + 1) * 2;
                    compz.MoveNewLine();
                }
                if (!internalCache.ContainsKey(ParentStatus.FavoredUsers[i].IconUri))
                    Bridge.ImageManager.ReserveImage(ParentStatus.FavoredUsers[i].IconUri, false);
            }
            //end
            compz.MoveNewLine();
            compz.SetCurrentLineHeight(innerPadding + 1 + outerMargin);
            compz.MoveNewLine();
        }

        public override void Draw(Graphics g, CompositeDescriptor desc)
        {
            lock (areaLocker)
            {
                areas.Clear();
                if (ParentStatus.FavoredUsers == null || ParentStatus.FavoredUsers.Length == 0)
                    return;
                Rectangle target = new Rectangle(desc.LeftTop, new Size(desc.ClientWidth, 0));
                target.X += outerMargin;
                target.Y += desc.Heights[0] + outerMargin;
                target.Width -= outerMargin * 2;
                int actualWidth = target.Width - (innerPadding + 1) * 2;
                int renderable = (int)Math.Floor((double)actualWidth / pictWidth);
                int lines = (int)Math.Ceiling(ParentStatus.FavoredUsers.Length / (double)renderable);
                target.Height = lines * pictHeight + (innerPadding + 1) * 2;
                g.FillRectangle(Brushes.White, target);

                //draw frame
                Point[] outerPoints = new[] { 
                new Point(target.Left, target.Bottom),
                new Point(target.Right, target.Bottom),
                new Point(target.Right, target.Top)};
                using (Pen p = new Pen(Color.FromArgb(255, 160, 0)))
                    g.DrawLines(p, outerPoints);

                outerPoints = new[] { 
                new Point(target.Left, target.Bottom),
                new Point(target.Left, target.Top),
                new Point(target.Right, target.Top)};
                using (Pen p = new Pen(Color.FromArgb(255, 208, 102)))
                    g.DrawLines(p, outerPoints);

                Point start = target.Location;
                start.X += innerPadding;
                start.Y += innerPadding;
                lock (dictionaryLocker)
                {
                    int gctor = 0;
                    for (int l = 0; l < lines; l++)
                    {
                        for (int x = 0; x < renderable && gctor < ParentStatus.FavoredUsers.Length; x++, gctor++)
                        {
                            Rectangle r = new Rectangle(start, new Size(pictWidth, pictHeight));
                            r.X += x * pictWidth;
                            r.Y += l * pictHeight;
                            areas.Add(new DescriptableAreas()
                            {
                                Area = r,
                                Description = ParentStatus.FavoredUsers[gctor].Name + "(@" + ParentStatus.FavoredUsers[gctor].Id + ")",
                                LinkUser = ParentStatus.FavoredUsers[gctor]
                            });
                            if (internalCache.ContainsKey(ParentStatus.FavoredUsers[gctor].IconUri))
                            {
                                if (internalCache[ParentStatus.FavoredUsers[gctor].IconUri] != null)
                                    g.DrawImage(internalCache[ParentStatus.FavoredUsers[gctor].IconUri], r);
                                else
                                {
                                    r.Width--;
                                    r.Height--;
                                    g.DrawRectangle(Pens.Red, r);
                                }
                            }
                            else
                            {
                                if (ParentStatus.FavoredUsers[gctor].IconUri == null)
                                {
                                    r.Width--;
                                    r.Height--;
                                    g.DrawRectangle(Pens.Red, r);
                                }
                                else
                                {
                                    if (Bridge.ImageManager.IsCacheExists(ParentStatus.FavoredUsers[gctor].IconUri))
                                    {
                                        Image img = Bridge.ImageManager.GetImage(ParentStatus.FavoredUsers[gctor].IconUri, false);
                                        internalCache.Add(ParentStatus.FavoredUsers[gctor].IconUri, img);
                                        if (img != null)
                                            g.DrawImage(img, r);
                                        else
                                        {
                                            r.Width--;
                                            r.Height--;
                                            g.DrawRectangle(Pens.Red, r);
                                        }
                                    }
                                    else
                                    {
                                        Bridge.ImageManager.GetImageCallback(
                                            ParentStatus.FavoredUsers[gctor].IconUri,
                                            false,
                                            new Krile.Kernel.Bridges.GetImageCallbackDelegate(ImgDlCallback));
                                        r.Width--;
                                        r.Height--;
                                        g.DrawRectangle(Pens.ForestGreen, r);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public override void Activate()
        {
        }

        public override void Release()
        {
            lock (dictionaryLocker)
            {
                foreach(var k in internalCache.Keys)
                {
                    if (internalCache[k] != null)
                        internalCache[k].Dispose();
                }
                internalCache.Clear();
            }
        }

        string prevDesc = null;
        public override string HelptipText
        {
            get
            {
                if (ParentStatus == null || ParentStatus.FavoredUsers == null)
                    return null;
                else
                    return prevDesc;
            }
        }

        public override bool HitTest(Point position)
        {
            lock (areaLocker)
            {
                foreach (var a in areas)
                {
                    if(a.Area.HitTest(position))
                    {
                        prevDesc = a.Description;
                        return true;
                    }
                }
            }
            return false;
        }

        public override void OnMouseEnter(object sender, ChainMouseEventArgs e)
        {
            if(ParentForm != null)
                ParentForm.SetCursor(Cursors.Hand);
        }

        public override void OnMouseClick(object sender, ChainMouseEventArgs e)
        {
            var u = PointingUser(e);
            if (u == null) return;
            Bridge.CommonOperation.CallBrowser("http://wassr.jp/user/" + u.Id);
        }

        User PointingUser(ChainMouseEventArgs e)
        {
            if (ParentStatus == null || ParentStatus.FavoredUsers == null || areas == null) return null;
            lock (areaLocker)
            {
                foreach (var a in areas)
                {
                    if ((a.Area.Left <= e.X && a.Area.Right >= e.X) &&
                        (a.Area.Top <= e.Y && a.Area.Bottom >= e.Y))
                    {
                        return a.LinkUser;
                    }
                }
            }
            return null;
        }

        public override void OnMouseLeave(object sender, ChainMouseEventArgs e)
        {
            if(ParentForm != null)
                ParentForm.SetCursor(Cursors.Default);
        }
    }
}
